﻿/**
 * @brief 用于多线程的tcp client
 * @author Zr
 * @date 20230221
 */
#pragma once

#include <QHostAddress>
#include <QMutex>
#include <QObject>
#include <QTcpSocket>
#include <QThread>
#include <QWaitCondition>
#include <functional>

#include "QtTcpMultithreading_global.h"

namespace ZTcp {
class TcpClient_T_Private;
/**
 * @brief 用于多线程的tcp client
 */
class QTTCPMULTITHREADING_EXPORT TcpClient_T : public QObject {
  Q_OBJECT
 public:
  /**
   * @brief 构造函数
   * @param socketDescriptor server接收到的socket handle,默认-1时自动建立
   * @param useTaskPool 是否使用多线程线程池,false时线程池只用1个线程,保证顺序执行任务
   */
  explicit TcpClient_T(QObject* parent = nullptr, bool useTaskPool = true, qintptr socketDescriptor = -1);

  ~TcpClient_T() override;

  /**
   * @brief 指定socket自身的ip port
   * @param address socket自身的ip
   * @param port socket自身的port
   * @return
   */
  void bind(const QHostAddress& address, quint16 port = 0);

  /**
   * @brief 连接到指定的server
   * @param address server的ip
   * @param port server的port
   */
  void connectToHost(const QHostAddress& address, quint16 port);

  /**
   * @brief 开始运行并进行连接
   */
  void start();

  /**
   * @brief 当接收到一帧信息时进行处理
   * @param f 回调处理函数
   */
  void read(std::function<void(const QByteArray&)> f);

  /**
   * @brief 是否已经连接
   * @return true表示已经连接
   */
  bool isConnected();

  /**
   * @brief 写入消息
   * @param arg 信息
   */
  void write(const QByteArray& arg);

  /**
   * @brief 同步写入数据
   * @param ptr 消息指针
   * @param size 消息大小
   */
  void writeAsync(const QByteArray& arg);

  /**
   * @brief 写入消息指针+大小,需要调用者保证数据可以安全到达多线程并且等待写入完毕
   * @param ptr 消息指针
   * @param size 消息大小
   */
  void write(char* ptr, int size);

  /**
   * @brief 同步写入数据
   * @param ptr 消息指针
   * @param size 消息大小
   */
  void writeAsync(char* ptr, int size);

  /**
   * @brief 返回socket自身绑定的ip
   * @return socket自身绑定的ip
   */
  const QHostAddress& localAddress() const;

  /**
   * @brief 返回socket自身绑定的port
   * @return socket自身绑定的port
   */
  quint16 localPort() const;

  /**
   * @brief 返回socket对端的ip
   * @return socket对端ip
   */
  QHostAddress peerAddress() const;

  /**
   * @brief 返回socket对端的port
   * @return socket对端的port
   */
  quint16 peerPort() const;

  /**
   * @brief 是否当前的tcp处于繁忙状态
   * @return true表示繁忙
   */
  bool isBusy();

 private:
  /** @brief 私有实现的指针 */
  TcpClient_T_Private* p_;

  /** @brief 私有实现运行的多线程 */
  QThread tcpClienPrivateThread_;

  /** @brief 用于等待数据发送完毕的条件变量 */
  QWaitCondition* waitDataTrans_;

  /** @brief 锁,用于等待数据发送完毕 */
  QMutex* waitDataTransMutex_;

 signals:
  /**
    * @brief 写入数据到多线程中
    * @param arg 数据
    */
  void sigWrite(QByteArray arg);

  /**
    * @brief 写入原始数据到多线程中
    * @param ptr 消息指针
    * @param size 消息大小
    */
  void sigWritePtr(char* ptr, int size);

  /**
    * @brief 启动并初始化私有实例p_
    */
  void sigStart();

  /**
   * @brief 启动完成
   */
  void sigStartDone();

  /**
   * @brief 断开连接时发送信息
   */
  void sigDisconnected();
};
}// namespace ZTcp
